package com.example.ucenter.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.commonsutils.JwtUtils;
import com.example.common.commonsutils.MD5;
import com.example.common.exception.GuliException;
import com.example.ucenter.entity.Member;
import com.example.ucenter.entity.vo.LoginVO;
import com.example.ucenter.entity.vo.RegisterVO;
import com.example.ucenter.mapper.MemberMapper;
import com.example.ucenter.service.MemberService;
import com.example.ucenter.utils.HttpClientUtils;
import com.example.ucenter.utils.WxConstUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
 * @Author:tjf
 * @Description:
 */
@Service
public class MemberServiceImpl extends ServiceImpl<MemberMapper, Member> implements MemberService{
    @Resource
    private MemberMapper memberMapper;
    @Resource(name = "stringRedisTemplate")
    private StringRedisTemplate redisTemplate;
    /**
     * 根据手机号和密码进行登录
     * @param member
     * @return
     */
    @Override
    public String loginByPhoneAndPassword(Member member) {
        // 参数判断
        String mobile = member.getMobile();
        String password = member.getPassword();
        if (StringUtils.isAnyBlank(mobile, password)){
            throw new GuliException(20001, "手机号或密码错误！");
        }

        // 查询数据库
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Member::getMobile, mobile)
                .eq(Member::getPassword, MD5.encrypt(password))
                .eq(Member::getIsDisabled, "0");
        Member result = memberMapper.selectOne(wrapper);
        // 查无此人
        if (result == null){
            throw new GuliException(20001, "手机号或密码错误！");
        }

        // 生成token 注意：区分member和result
        String token = JwtUtils.getJwtToken(result.getId(), result.getNickname());
        return token;
    }

    /**
     * 通过手机号和验证码注册
     * @param registerVO
     */
    @Override
    public void registerByPhoneAndCode(RegisterVO registerVO) {
        // 参数判断
        String mobile = registerVO.getMobile();
        String password = registerVO.getPassword();
        String code = registerVO.getCode();
        String nickName = registerVO.getNickName();
        if (StringUtils.isAnyBlank(mobile, password, code, nickName) == true){
            throw new GuliException(20001, "注册失败，存在参数为空");
        }

        // 判断手机号是否注册过
        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Member::getMobile, mobile);
        if (memberMapper.selectCount(wrapper) > 0) {
            throw new GuliException(20001, "该手机号已被注册");
        }

        // 判断验证码是否正确
        if (redisTemplate.hasKey("smsservice::register:" + mobile) == false){
            throw new GuliException(20001, "验证码不正确");
        }

        // 删除redis中的验证码
        redisTemplate.delete("smsservice::register:" + mobile);

        // 写入数据库 密码MD5
        Member member = new Member();
        member.setMobile(mobile);
        member.setPassword(MD5.encrypt(password));
        member.setAvatar("https://guli-file-190513.oss-cn-beijing.aliyuncs.com/avatar/default.jpg");
        member.setIsDisabled(0);
        memberMapper.insert(member);
    }

    /**
     * 根据token，获取用户的信息
     * @param token
     * @return
     */
    @Override
    public LoginVO getUserInfoByToken(String token) {
        try{
            // 获取用户id并做判断
            String memberId = JwtUtils.getMemberIdByJwtToken(token);
            if (StringUtils.isBlank(memberId)){
                throw new GuliException(20001, "Token无效，请重新登录");
            }
            // 查询数据库
            Member member = memberMapper.selectById(memberId);
            //todo_tjf (tjf,2024/2/27,Com_T)有可能token仍有效，但用户被删除了
            LoginVO result = new LoginVO();
            BeanUtils.copyProperties(member, result);
            return result;
        }catch (Exception e){
            e.printStackTrace();
            throw new GuliException(20001, "token无效，请重新登录");
        }
    }

    /**
     * 通过微信扫码登录
     * @param code
     * @return
     */
    @Override
    public String loginByWxCode(String code) {
        ObjectMapper objectMapper = new ObjectMapper();
        // 获取用户的个人信息
        // 1 格式化获取access_token的url
        String urlForAT = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code";
        urlForAT = String.format(urlForAT, WxConstUtils.WX_OPEN_APP_ID, WxConstUtils.WX_OPEN_APP_SECRET, code);

        String token = "";
        // 2 请求access_token
        try {
            Map<String, Object> resultForATMap = objectMapper.readValue(HttpClientUtils.get(urlForAT), Map.class);
            String accessToken = (String) resultForATMap.get("access_token");
            String openid = (String) resultForATMap.get("openid");
            // 3 格式化获取用户信息url
            String urlForUI = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s";
            urlForUI = String.format(urlForUI, accessToken, openid);

            // 4请求用户个人信息
            Map<String, Object> resultForUIMap = objectMapper.readValue(HttpClientUtils.get(urlForUI), Map.class);
            // 是注册？是登录？
            token = registerOrLogin(resultForUIMap);
            // 返回可以登录的标志 --> 前端收到标志后，
        } catch (Exception e) {
            e.printStackTrace();
            new GuliException(20001, "系统网络繁忙，请稍后重试");
        }
        return token;
    }

    /**
     * 统计指定日期的会员注册数
     * @param dayStr
     * @return
     */
    @Override
    public Integer statisticsRegisterMember(String dayStr) {
        // 查询指定日期的会员注册数
        Integer count = memberMapper.statisticsRegisterMember(dayStr);
        return count;
    }

    /**
     * 微信用户扫码登录后，判断其是登录还是注册
     * @param resultForUIMap
     * @return
     */
    private String registerOrLogin(Map<String, Object> resultForUIMap) {
        String openid = (String)resultForUIMap.get("openid"); // 微信用户标示，是唯一的
        String nickname = (String)resultForUIMap.get("nickname");
        String avatar = (String)resultForUIMap.get("headimgurl");

        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Member::getOpenid, openid);
        Member member = memberMapper.selectOne(wrapper);

        String id = "";
        if (member == null){ // 注册
            Member registerMember = new Member();
            registerMember.setOpenid(openid).setAvatar(avatar).setIsDisabled(0).setNickname(nickname);
            memberMapper.insert(registerMember);
            id = registerMember.getId();
        }else{ // 登录
            Member loginMember = new Member();
            loginMember.setNickname(nickname).setAvatar(avatar);
            memberMapper.update(loginMember, wrapper);
            id = member.getId();
        }
        // 颁发token
        return JwtUtils.getJwtToken(id, nickname);
    }
}
